package com.wondream.myframework.app.common.excel.processor;

import com.google.common.collect.Maps;
import com.wondream.myframework.app.common.constant.Constants;
import com.wondream.myframework.app.common.excel.context.CfssPoiExporterContext;
import com.wondream.myframework.app.common.excel.domain.MultiRowModel;
import com.wondream.myframework.app.common.exception.BusinessExeceptionCode;
import com.wondream.myframework.app.common.util.JacksonUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <poi:foreach></poi:foreach>的处理器
 */
public class ForeachRowProcessor implements RowProcessor {
    @Override
    public int dealRow(XSSFRow currentRow, CfssPoiExporterContext peContext) {
        XSSFCell beginCell = currentRow.getCell(support(currentRow));

        //从beginCell中找出list key
        String beginCellContent = beginCell.getStringCellValue();
        Matcher ma = Pattern.compile(Constants.POI_FOREACH_START_REGEXP).matcher(beginCellContent);
        String key = null;
        if (ma.find()) {
            key = ma.group(1).trim();
        } else {
            throw BusinessExeceptionCode.SYS_ERROR.exp();
        }

        MultiRowModel tpRow = new MultiRowModel();
        tpRow.setListKey(key);
        tpRow.setBegin(beginCell.getRowIndex());
        TreeMap<Integer, Map<Integer, Object>> cellMap = new TreeMap<>();
        int beginRowNum = beginCell.getRow().getRowNum();
        Pattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);
        Pattern postPattern = Pattern.compile(Constants.POI_FOREACH_END_REGEXP);
        while (beginRowNum <= beginCell.getSheet().getLastRowNum() && null == tpRow.getEnd()) {
            XSSFRow row = beginCell.getSheet().getRow(beginRowNum);
            if (row == null) {
//                throw BusinessExeceptionCode.SYS_ERROR.exp();
            }
            HashMap<Integer, Object> map = Maps.newHashMap();
            short end = row.getLastCellNum();
            for (int k = 0; k <= end; k++) {
                XSSFCell cell = row.getCell(k);
                if (null == cell) {
                    continue;
                }
                String cellValue = cell.getRichStringCellValue().getString().trim();
                if (StringUtils.isBlank(cellValue)) {
                    continue;
                }
                String value = cellValue;
                Matcher preMatcher = prePattern.matcher(cellValue);
                if (preMatcher.find()) {
                    value = preMatcher.replaceAll("");
                }
                Matcher postMatcher = postPattern.matcher(cellValue);
                if (postMatcher.find()) {
                    value = postMatcher.replaceAll("");
                    tpRow.setEnd(beginRowNum);
                }
                // 存放<单元格列号，单元格内容>。单元格内容是除去tag之外的
                map.put(k, value);
            }
            cellMap.put(beginRowNum, map);
            beginRowNum++;
        }
        tpRow.setCellMap(cellMap);
        Object rootObject = peContext.getRootObjectMap().get(key);
        if (!(rootObject instanceof List)) {
            throw BusinessExeceptionCode.SYS_ERROR.exp();
        }
        List<?> ls = (List<?>) rootObject;
        // transfer
        setMultiData(beginCell, key, ls, tpRow, peContext);
        return CollectionUtils.isEmpty(ls) ? 1 : ls.size() * (tpRow.getEnd() - tpRow.getBegin() + 1);
    }

    // 进行拷贝和赋值
    private void setMultiData(XSSFCell cell, String foreachKey, List<?> ls, MultiRowModel tpRow, CfssPoiExporterContext peContext) {
        XSSFSheet sheet = cell.getSheet();
        int multiRow = tpRow.getEnd() - tpRow.getBegin() + 1;
        // 行往下移
        if (ls.size() > 1) {
            sheet.shiftRows(tpRow.getEnd() + 1, sheet.getLastRowNum() + 3, (ls.size() - 1) * multiRow, true, false);
        }
        Map<Integer, Map<Integer, Object>> cellMap = tpRow.getCellMap();
        if (ls.isEmpty()) {
            cellMap.keySet().forEach(k -> {
                XSSFRow curRow = null;
                curRow = sheet.getRow(k);
                final XSSFRow curRowFinal = curRow;
                Map<Integer, Object> map = cellMap.get(k);
                map.keySet().forEach(key1 -> {
                    XSSFCell c = curRowFinal.getCell(key1);
                    c.setCellValue("");
                });
            });
            return;
        }
        for (int i = 0; i < ls.size(); i++) {
            Object itemObject = ls.get(i);
            final int ii = i;
            cellMap.keySet().forEach(k -> {
                XSSFRow curRow = null;
                if (ii == 0) {
                    curRow = sheet.getRow(k);
                } else {
                    curRow = sheet.createRow(ii * multiRow + k);
                    //拷贝样式
                    copyCellStyle(sheet.getRow(k), curRow);
                    //合并
                    copyMergeRegion(sheet, k, ii * multiRow + k);
                }

                //处理当前行里面的每个单元格，替换内容
                Map<Integer, Object> map = cellMap.get(k);
                final XSSFRow curRowFinal = curRow;
                map.keySet().forEach(key1 -> {
                    String cellContent = map.get(key1) == null ? "" : (String) map.get(key1);
                    XSSFCell c = curRowFinal.getCell(key1);
                    if (StringUtils.equals(Constants.CFSS_ROWNO, cellContent.trim())) {
                        c.setCellValue(ii);
                    } else {
                        c.setCellValue(parseValue(cellContent, ii, foreachKey, peContext));
                    }
                });
            });
            peContext.getRootObjectMap().remove("cfssItem");
        }
    }

    private static Map transferObjToJson(Object o) {
        return JacksonUtil.toMap(JacksonUtil.toJson(o));
    }

    private static String parseValue(String cellContent, int index, String foreachKey, CfssPoiExporterContext peContext) {
        //处理${key}
        return DefaultRowProcessor.resolveItem(cellContent, index, foreachKey, peContext);
    }

    //拷贝样式
    private static void copyCellStyle(XSSFRow src, XSSFRow des) {
        for (int j = src.getFirstCellNum(); j < src.getLastCellNum(); j++) {
            des.createCell(j).setCellStyle(src.getCell(j).getCellStyle());
        }
    }

    //拷贝合并单元格
    private static void copyMergeRegion(XSSFSheet sheet, int srcRow, int desRow) {
        for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
            CellRangeAddress oldRegion = sheet.getMergedRegion(j);
            if ((oldRegion.getFirstRow() == srcRow)&&(oldRegion.getLastRow() == srcRow)) {
                int oldFirstCol = oldRegion.getFirstColumn();
                int oldLastCol = oldRegion.getLastColumn();
                CellRangeAddress newRegion = new CellRangeAddress(desRow, desRow, oldFirstCol, oldLastCol);
                sheet.addMergedRegion(newRegion);
            }
        }
    }

    @Override
    public int support(XSSFRow row) {
        for (int k = 0; k < row.getLastCellNum(); k++) {
            XSSFCell cell = row.getCell(k);
            if (null != cell && CellType.STRING == cell.getCellType()) {
                String content = cell.getStringCellValue().trim();
                Pattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);
                Matcher matcher = prePattern.matcher(content);
                if (matcher.find()) {
                    return k;
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        String content = "<poi:foreach list=\"list\">#{index}";
//        String content = "<poi:foreach list=\"list\">";
        boolean flag = content.matches("<poi:foreach\\s+list=\"(\\w+)\">");
        System.out.println(flag);

        Pattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);
        Matcher matcher = prePattern.matcher(content);
        boolean b = matcher.find();
        System.out.println(b);
        System.out.println(matcher.replaceAll(""));
    }
}
